﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace LargeScreen.WPF.Controls
{
    /// <summary>
    /// Meter.xaml 的交互逻辑
    /// </summary>
    public partial class Meter : UserControl
    {

        /// <summary>
        /// 最小刻度
        /// </summary>
        public double Minimum
        {
            get { return (double)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Minimum.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(Meter), new PropertyMetadata(0.0));

        /// <summary>
        /// 最大刻度
        /// </summary>
        public double Maximum
        {
            get { return (double)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Maximum.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(Meter), new PropertyMetadata(100.0));


        /// <summary>
        /// 圆弧外间距
        /// </summary>
        public double RoundOutMargin
        {
            get { return (double)GetValue(RoundOutMarginProperty); }
            set { SetValue(RoundOutMarginProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RoundOutMargin.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RoundOutMarginProperty =
            DependencyProperty.Register("RoundOutMargin", typeof(double), typeof(Meter), new PropertyMetadata(2.0));



        /// <summary>
        /// 刻度距离圆弧的间距
        /// </summary>
        public double ScaleOutMargin
        {
            get { return (double)GetValue(ScaleOutMarginProperty); }
            set { SetValue(ScaleOutMarginProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleOutMargin.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleOutMarginProperty =
            DependencyProperty.Register("ScaleOutMargin", typeof(double), typeof(Meter), new PropertyMetadata(2.0));


        /// <summary>
        /// 刻度最小步长
        /// </summary>
        public double ScaleMinStep
        {
            get { return (double)GetValue(ScaleMinStepProperty); }
            set { SetValue(ScaleMinStepProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleMinStep.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleMinStepProperty =
            DependencyProperty.Register("ScaleMinStep", typeof(double), typeof(Meter), new PropertyMetadata(1.0));

        /// <summary>
        /// 最小刻度长度
        /// </summary>
        public double MinScaleLength
        {
            get { return (double)GetValue(MinScaleLengthProperty); }
            set { SetValue(MinScaleLengthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MinScaleLength.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MinScaleLengthProperty =
            DependencyProperty.Register("MinScaleLength", typeof(double), typeof(Meter), new PropertyMetadata(6.0));



        /// <summary>
        /// 值
        /// </summary>
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(Meter), new PropertyMetadata(0.0, new PropertyChangedCallback(OnValueChanged)));


        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as Meter).UpdatePointer();
        }

        private void UpdatePointer()
        {
            double step = 270 / (Maximum - Minimum);
            double angle = (Value - Minimum) * step + 135;
            //添加动画
            var da = new DoubleAnimation(angle, new TimeSpan(0, 0, 0, 0, 200));
            this.pointerAngle.BeginAnimation(RotateTransform.AngleProperty, da);
        }


        /// <summary>
        /// 单位
        /// </summary>
        public string Unit
        {
            get { return (string)GetValue(UnitProperty); }
            set { SetValue(UnitProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Unit.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UnitProperty =
            DependencyProperty.Register("Unit", typeof(string), typeof(Meter), new PropertyMetadata(""));



        /// <summary>
        /// 名称
        /// </summary>
        public string Header
        {
            get { return (string)GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Header.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderProperty =
            DependencyProperty.Register("Header", typeof(string), typeof(Meter), new PropertyMetadata(""));




        public Meter()
        {
            InitializeComponent();
            this.SizeChanged += Meter_SizeChanged;
        }

        private void Meter_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.back_border.Width = Math.Min(this.RenderSize.Width, this.RenderSize.Height);
            this.back_border.Height = Math.Min(this.RenderSize.Width, this.RenderSize.Height);
            this.back_border.CornerRadius = new CornerRadius(this.back_border.Width / 2);

            //半径
            double radius = this.back_border.Width / 2;

            //大小修改会引起变化，不断往里面加，所有这里需要清空
            this.canvasPlate.Children.Clear();
            if (radius <= 0) return;

            //仪表边框
            double pathMargin = this.pathBorder.StrokeThickness + RoundOutMargin;
            string borderPathData = $"M{pathMargin} {radius} A{radius - pathMargin} {radius - pathMargin} 0 1 1 {radius} {2 * radius - pathMargin}";
            this.pathBorder.Data = PathGeometry.Parse(borderPathData);

            //刻度
            double scaleNum = (Maximum - Minimum) / ScaleMinStep;
            double textNum = Minimum;
            for (int i = 0; i <= scaleNum; i++)
            {
                var line = new Line();
                line.Stroke = Brushes.White;
                line.StrokeThickness = 1.0;

                line.X1 = radius + (radius - pathMargin - ScaleOutMargin) * Math.Cos((270 / scaleNum * i + 135) * (Math.PI / 180));
                line.Y1 = radius + (radius - pathMargin - ScaleOutMargin) * Math.Sin((270 / scaleNum * i + 135) * (Math.PI / 180));

                double scaleLen = 0;
                if (i % 10 == 0)
                {
                    scaleLen = MinScaleLength + MinScaleLength / 2;

                    //文本数值
                    var text = new TextBlock();
                    text.Text = textNum.ToString("0");
                    text.FontSize = 10;
                    text.Foreground = Brushes.White;
                    Canvas.SetLeft(text, radius + (radius - pathMargin - ScaleOutMargin - MinScaleLength - scaleLen * 3) * Math.Cos((270 / scaleNum * i + 135) * (Math.PI / 180)) - 6);
                    Canvas.SetTop(text, radius + (radius - pathMargin - ScaleOutMargin - MinScaleLength - scaleLen * 3) * Math.Sin((270 / scaleNum * i + 135) * (Math.PI / 180)) - 6);
                    this.canvasPlate.Children.Add(text);

                    textNum += 10;
                }
                else if (i % 5 == 0)
                {
                    scaleLen = MinScaleLength/2;
                }

                line.X2 = radius + (radius - pathMargin - ScaleOutMargin - MinScaleLength - scaleLen) * Math.Cos((270 / scaleNum * i + 135) * (Math.PI / 180));
                line.Y2 = radius + (radius - pathMargin - ScaleOutMargin - MinScaleLength - scaleLen) * Math.Sin((270 / scaleNum * i + 135) * (Math.PI / 180));

                this.canvasPlate.Children.Add(line);
            }

            //指针
            string pointerData = $"M {radius} {radius + 2} {this.back_border.Width * 0.95} {radius} {radius} {radius - 2}";
            this.pointer.Data = PathGeometry.Parse(pointerData);
        }

    }
}
